package com.jzo2o.customer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.publics.MapApi;
import com.jzo2o.api.publics.dto.response.LocationResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.NumberUtils;
import com.jzo2o.common.utils.StringUtils;
import com.jzo2o.customer.mapper.AddressBookMapper;
import com.jzo2o.customer.model.domain.AddressBook;
import com.jzo2o.customer.model.dto.request.AddressBookPageQueryReqDTO;
import com.jzo2o.customer.model.dto.request.AddressBookUpsertReqDTO;
import com.jzo2o.customer.service.IAddressBookService;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 地址薄 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-06
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements IAddressBookService {


    @Autowired
    private AddressBookMapper addressBookMapper;

    //引入高德远程调用
    @Autowired
    private MapApi mapApi;


    @Override
    public List<AddressBookResDTO> getByUserIdAndCity(Long userId, String city) {

        List<AddressBook> addressBooks = lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getCity, city)
                .list();
        if(CollUtils.isEmpty(addressBooks)) {
            return new ArrayList<>();
        }
        return BeanUtils.copyToList(addressBooks, AddressBookResDTO.class);
    }

    /**
     * 获取默认地址
     * @return
     */
    @Override
    public AddressBookResDTO getDefaultAddress() {
        //根据用户id查询地址表,注意构造条件用户id以及地址表默认地址为1
        //注意this.lambdaquery调用的是继承中的mapper方法
        AddressBook bookResDTO = this.lambdaQuery()
                .eq(AddressBook::getUserId, UserContext.currentUserId())
                .eq(AddressBook::getIsDefault, 1)
                .one();
        if(ObjectUtil.isNull(bookResDTO)){
            throw new ForbiddenOperationException("请先添加默认地址");
        }
        AddressBookResDTO addressBookResDTO = BeanUtil.copyProperties(bookResDTO, AddressBookResDTO.class);
        return addressBookResDTO;
    }


    /**
     * 新增地址簿业务层
     * @param addressBook
     */
    @Override
    public void add(AddressBookUpsertReqDTO addressBook) {
        /**
         * 思路：先拿到用户id，根据用户id查询地址表addrebook，插入新的地址信息，注意
         * 位置字段location需要自行拆分，如果有，自己拆，如果没有需要调用高德接口获取经纬度插入
         * 步骤：1，根据用户id和默认地址信息查询地址表，拿到默认地址信息
         *     2，分析参数如果默认地址字段是1，表示需要将新地址设置为默认地址，修改原默认地址的默认字段为0
         *     3，分析经纬度，如果传递了location则拆分成对应经纬度，没有则调用高德接口
         *     4，插入新的地址
         */
        //1.根据用户id和默认地址信息查询地址表
        Long userId = UserContext.currentUserId();
        AddressBook abook = this.lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getIsDefault, 1)
                .one();
        if(ObjectUtil.isNotNull(abook)&&addressBook.getIsDefault()==1){
            //原用户存在默认地址，并且新地址要设置为默认地址,则修改原默认地址
            abook.setIsDefault(0);
            this.updateById(abook);
        }
        //todo 整理经纬度拆分以及调用高德封装经纬度
        String lon= "";
        String lat= "";
        if(addressBook.getLocation()!=null&&addressBook.getLocation()!=""){
            //需要拆分经纬度
            lon = addressBook.getLocation().split(",")[0];
            lat = addressBook.getLocation().split(",")[1];
        }
        else {
            //调用高德接口获取经纬度\
            String address = addressBook.getProvince() + addressBook.getCity() + addressBook.getCounty()
                    + addressBook.getAddress();
            LocationResDTO locationByAddress = mapApi.getLocationByAddress(address);
            String location = locationByAddress.getLocation();
            lon = location.split(",")[0];
            lat=location.split(",")[1];
        }
        AddressBook abook2 = new AddressBook();
        BeanUtil.copyProperties(addressBook,abook2);
        //todo hutool提供的字符->数字转换整理
        abook2.setLat(NumberUtil.parseDouble(lat));
        abook2.setLon(NumberUtil.parseDouble(lon));
        abook2.setUserId(userId);
        baseMapper.insert(abook2);
    }


    //地址簿分页 todo 要整理
    @Override
    public PageResult<AddressBookResDTO> findByPage(AddressBookPageQueryReqDTO addressBookPageQueryReqDTO) {

        //设置分页参数
        Page<AddressBook> page = PageUtils.parsePageQuery(addressBookPageQueryReqDTO, AddressBook.class);
        //设置条件
        LambdaQueryWrapper<AddressBook> wrapper = Wrappers.<AddressBook>lambdaQuery().eq(AddressBook::getUserId, UserContext.currentUserId());
        //分页查询
        Page<AddressBook> bookPage = baseMapper.selectPage(page, wrapper);


        return PageUtils.toPage(bookPage, AddressBookResDTO.class);
    }


    //地址簿详情，根据id查询地址
    @Override
    public AddressBookResDTO findById(Long id) {
        AddressBook addressBook = baseMapper.selectById(id);
        if(ObjectUtil.isNull(addressBook)){
            throw new ForbiddenOperationException("该地址簿不存在");
        }
        AddressBookResDTO addressBookResDTO = BeanUtil.copyProperties(addressBook, AddressBookResDTO.class);
        return addressBookResDTO;
    }

    //编辑地址，同新增基本逻辑类似 todo 非常重要，整理
    @Override
    public void updateAddressById(Long id, AddressBookUpsertReqDTO addressBook) {
        //思路，同新增，要分析经纬度是否传入，没有的话直接调用更新方法，有的话需要转化经纬度信息，在更新
        //1，如果新增地址设为默认，则将其他地址设为非默认
        if(addressBook.getIsDefault()==1){
            this.lambdaUpdate().eq(AddressBook::getUserId, UserContext.currentUserId())
                    .set(AddressBook::getIsDefault,0)
                    .update();
        }
        AddressBook book = BeanUtil.copyProperties(addressBook, AddressBook.class);
        book.setId(id);
        //经纬度的判断,若为空则组装地址
        if(ObjectUtil.isEmpty(addressBook.getLocation())){
            String commonAddress = addressBook.getProvince() + addressBook.getCity()
                    + addressBook.getCounty() + addressBook.getAddress();
            LocationResDTO locationResDTO = mapApi.getLocationByAddress(commonAddress);
            String location = locationResDTO.getLocation();
            addressBook.setLocation( location);
        }
        //此处一定有位置值，可以拆开封装经纬度
        book.setLon(NumberUtil.parseDouble(addressBook.getLocation().split(",")[0]));
        book.setLat(NumberUtil.parseDouble(addressBook.getLocation().split(",")[1]));
        baseMapper.updateById(book);
    }


    //批量删除id
    @Override
    public void removeAddressByIds(List<Long> ids) {
        this.removeByIds(ids);
    }


    //设置默认地址 todo 整理简化方法
    @Override
    public void setDefaultAddress(Long id, Integer flag) {
        //思路：先查询是否当前用户存在默认地址，若没有则根据参数判断是否设置为默认地址
        /*AddressBook addressBook = this.lambdaQuery()
                .eq(AddressBook::getUserId, UserContext.currentUserId())
                .eq(AddressBook::getIsDefault, 1)
                .one();
        if(ObjectUtil.isNull(addressBook)&&flag==1){
            //当前用户没有默认地址，且需要将地址设置为默认地址
                //需要将当前地址设置为默认地址
                this.lambdaUpdate()
                        .eq(AddressBook::getId, id)
                        .set(AddressBook::getIsDefault, 1)
                        .update();
        }
        else if(ObjectUtil.isNotNull(addressBook)&&flag==1){
            //当前用户有默认地址，且需要将传入的地址设置为默认地址，需要修改原默认地址状态，然后修改新地址默认状态
            addressBook.setIsDefault(0);
            this.updateById(addressBook);
            this.lambdaUpdate()
                    .eq(AddressBook::getId, id)
                    .set(AddressBook::getIsDefault, 1)
                    .update();
        }*/

        //方法简化
        if(flag==1){
            this.lambdaUpdate()
                    .eq(AddressBook::getUserId, UserContext.currentUserId())
                    .set(AddressBook::getIsDefault, 0)
                    .update();
        }
        AddressBook addressBook = new AddressBook();
        addressBook.setId(id);
        addressBook.setIsDefault(flag);
        this.updateById(addressBook);
    }
}
